/*
 * @Author: wuzhouhai wzh200x@126.com
 * @Date: 2025-04-07 11:17:29
 * @LastEditors: wuzhouhai wzh200x@126.com
 * @LastEditTime: 2025-04-07 16:24:36
 * @FilePath: \tars\GDBServer\db\dbMysql\dbMysqlHelper.go
 * @Description:
 */
package dbMysql

import (
	"fmt"
	"time"

	"github.com/TarsCloud/TarsGo/tars/util/conf"
	"github.com/TarsCloud/TarsGo/tars/util/rogger"
	"github.com/wzh200x/hyperNexus/hyperNexusCommon"
	"github.com/wzh200x/hyperNexus/hyperNexusModel"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/schema"
)

type MysqlDBConfig struct {
	Host            string        // 数据库地址
	Port            int           // 数据库端口
	DBName          string        // 数据库名称
	User            string        // 数据库用户名
	Pass            string        // 数据库密码
	MaxOpenConns    int           // 最大连接数（默认100）
	MaxIdleConns    int           // 空闲连接数（默认10）
	ConnMaxLifetime time.Duration // 连接生命周期（默认1小时）
	LogMode         int           // 日志模式
	SyncTabel       bool          // 是否同步表结构
	Prefix          string        // 表前缀
}

func (dbs *MysqlDBConfig) FormatConnectStr() string {
	return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=10s", dbs.User, dbs.Pass, dbs.Host, dbs.Port, dbs.DBName)
}

func (dbs *MysqlDBConfig) GetConf(sConf *conf.Conf) {
	dbs.Host = sConf.GetString("server/db<host>")
	dbs.Port = sConf.GetInt("server/db<port>")
	dbs.DBName = sConf.GetString("server/db<dbname>")
	dbs.User = sConf.GetString("server/db<user>")
	dbs.Pass = sConf.GetString("server/db<pass>")
	dbs.MaxOpenConns = sConf.GetIntWithDef("server/db<maxopenconns>", 100)
	dbs.MaxIdleConns = sConf.GetIntWithDef("server/db<maxidleconns>", 10)
	dbs.ConnMaxLifetime = time.Duration(sConf.GetIntWithDef("server/db<connmaxlifetime>", 3600)) * time.Second
	dbs.LogMode = sConf.GetIntWithDef("server/db<logmode>", 1)
	dbs.SyncTabel = sConf.GetBoolWithDef("server/db<synctabel>", false)
	dbs.Prefix = sConf.GetStringWithDef("server/db<prefix>", "")

	// 将配置信息打印到日志
	fmt.Printf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=10s&prefix=%s\n", dbs.User, dbs.Pass, dbs.Host, dbs.Port, dbs.DBName, dbs.Prefix)
}

type MysqlHelper struct {
	dbConfig *MysqlDBConfig
	DB       *gorm.DB
	Models   map[string]*hyperNexusModel.HyperNexusModel
	dbLogger *rogger.Logger
}

func (m *MysqlHelper) Init(sConf *conf.Conf) error {
	m.dbConfig.GetConf(sConf)
	// 创建日志
	m.dbLogger = hyperNexusCommon.HyperNexusLogIns.GetLogger("dbMysql")
	// 连接数据库
	dsn := m.dbConfig.FormatConnectStr()
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
		NamingStrategy: schema.NamingStrategy{
			TablePrefix: m.dbConfig.Prefix,
		},
	})
	if err != nil {
		return fmt.Errorf("failed to connect to database: %w", err)
	}

	// 设置连接池
	sqlDB, err := db.DB()
	if err != nil {
		return fmt.Errorf("failed to get database connection: %w", err)
	}
	sqlDB.SetMaxOpenConns(m.dbConfig.MaxOpenConns)
	sqlDB.SetMaxIdleConns(m.dbConfig.MaxIdleConns)
	sqlDB.SetConnMaxLifetime(m.dbConfig.ConnMaxLifetime)

	// 设置日志模式
	db.Logger.LogMode(logger.LogLevel(m.dbConfig.LogMode))
	m.DB = db
	return nil
}

func (m *MysqlHelper) RegisterModel(model *hyperNexusModel.HyperNexusModel) {
	if m.Models == nil {
		m.Models = make(map[string]*hyperNexusModel.HyperNexusModel)
	}
	model.SetTabelPrefix(m.dbConfig.Prefix)
	m.Models[model.Name] = model
}

func (m *MysqlHelper) SyncTableByName(modelName string) error {
	if m.dbConfig.SyncTabel {
		if modelName != "" {
			if model, ok := m.Models[modelName]; ok {
				return m.DB.AutoMigrate(model.EntityModelData)
			}
		}
	}
	return nil
}

func (m *MysqlHelper) SyncTable() error {
	if m.dbConfig.SyncTabel {
		for _, model := range m.Models {
			if model == nil {
				m.dbLogger.Warnf("model is nil")
				continue
			}
			if model.EntityModelData == nil {
				m.dbLogger.Warnf("%s model.EntityModelData is nil", model.Name)
				continue
			}
			if err := m.DB.Table(model.TableName()).AutoMigrate(model.EntityModelData); err != nil {
				return err
			}
			if model.ShardConfig != nil {
				for i := 0; i < model.ShardConfig.ShardNum; i++ {
					tName := model.ShareTabelName(i)
					if err := m.DB.Table(tName).AutoMigrate(model.EntityModelData); err != nil {
						return err
					}
				}
			}
		}
	}
	return nil
}

func (m *MysqlHelper) GetModelByName(modelName string) *hyperNexusModel.HyperNexusModel {
	if model, ok := m.Models[modelName]; ok {
		return model
	}
	return nil
}

func (m *MysqlHelper) Create(tabelName string, eData interface{}) error {
	if eData == nil {
		return fmt.Errorf("eData is nil")
	}

	return m.DB.Table(tabelName).Create(eData).Error
}

func (m *MysqlHelper) Update(tabelName string, eData interface{}) error {
	if eData == nil {
		return fmt.Errorf("eData is nil")
	}
	return m.DB.Table(tabelName).Save(eData).Error
}

func (m *MysqlHelper) Query(tabelName string, eData interface{}, where string, args ...interface{}) error {
	if eData == nil {
		return fmt.Errorf("eData is nil")
	}
	return m.DB.Table(tabelName).Where(where, args...).First(eData).Error
}

func (m *MysqlHelper) QueryAll(tabelName string, eData interface{}, where string, args ...interface{}) error {
	if eData == nil {
		return fmt.Errorf("eData is nil")
	}
	return m.DB.Table(tabelName).Where(where, args...).Find(eData).Error
}

func NewMysqlHelper() *MysqlHelper {
	dbConfig := &MysqlDBConfig{}
	ms := &MysqlHelper{
		dbConfig: dbConfig,
		Models:   make(map[string]*hyperNexusModel.HyperNexusModel),
	}
	return ms
}
